﻿/***************************************************************
 * 开发人员：网魂小兵@http://www.mozlite.com
 * 
 *  字符串扩展方法类型。
 * 
 * 最后修改：2011-10-19
 * ************************************************************/
namespace Mozlite
{
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Text.RegularExpressions;
    using System.Collections;
    using System.Globalization;
    using System.Collections.Specialized;

    /// <summary>
    /// 字符串辅助类。
    /// </summary>
    public static class StringUtility
    {
        #region compares
        /// <summary>
        /// 判断两个字符串是否相等。
        /// </summary>
        /// <param name="str">字符串。</param>
        /// <param name="text">对比文本字符串。</param>
        /// <param name="ignoreCase">是否忽略大小写。</param>
        /// <returns>如果相同返回<c>true</c>，否则返回<c>false</c>。</returns>
        public static bool IsMatched(this string str, string text, bool ignoreCase = true)
        {
            return string.Compare(str, text, ignoreCase) == 0;
        }
        /// <summary>
        /// 判断字符串是否为Email地址。
        /// </summary>
        /// <param name="email">当前字符串。</param>
        /// <returns>如果Email地址合法，则返回true。</returns>
        public static bool IsEmail(this string email)
        {
            return email.IsMatched(emailRegex);
        }
        /// <summary>
        /// 判断是否符合正则表达式。
        /// </summary>
        /// <param name="str">判断的字符串。</param>
        /// <param name="pattern">正则表达式。</param>
        /// <param name="options">正则表达式选项。</param>
        /// <returns>如果匹配返回<c>true</c>，否则返回<c>false</c>。</returns>
        public static bool IsMatched(this string str, string pattern, RegexOptions options)
        {
            if (string.IsNullOrEmpty(str) || string.IsNullOrEmpty(pattern))
                return false;
            return Regex.IsMatch(str, pattern, options);
        }
        /// <summary>
        /// 判断是否符合正则表达式。
        /// </summary>
        /// <param name="str">判断的字符串。</param>
        /// <param name="regex">正则表达式。</param>
        /// <returns>如果匹配返回<c>true</c>，否则返回<c>false</c>。</returns>
        public static bool IsMatched(this string str, Regex regex)
        {
            if (string.IsNullOrEmpty(str))
                return false;
            return regex.IsMatch(str.Trim());
        }
        #endregion

        #region splits
        /// <summary>
        /// 分割字符串。
        /// </summary>
        /// <typeparam name="T">分割后转换的类型。</typeparam>
        /// <param name="str">用于分割的字符串。</param>
        /// <param name="separator">分割字符。</param>
        /// <param name="options">是否移除空项。</param>
        /// <returns>返回分割后的列表。</returns>
        public static List<T> Split<T>(this string str, char[] separator, StringSplitOptions options = StringSplitOptions.RemoveEmptyEntries)
        {
            List<T> list = new List<T>();
            if (!string.IsNullOrEmpty(str))
            {
                foreach (string part in str.Split(separator, options))
                {
                    list.Add(part.ChangeTo<T>());
                }
            }
            return list;
        }
        /// <summary>
        /// 分割字符串。
        /// </summary>
        /// <typeparam name="T">分割后转换的类型。</typeparam>
        /// <param name="str">用于分割的字符串。</param>
        /// <param name="separator">分割字符串。</param>
        /// <param name="options">是否移除空项。</param>
        /// <returns>返回分割后的列表。</returns>
        public static List<T> Split<T>(this string str, string[] separator = null, StringSplitOptions options = StringSplitOptions.RemoveEmptyEntries)
        {
            List<T> list = new List<T>();
            if (!string.IsNullOrEmpty(str))
            {
                if (separator == null)
                    separator = new string[] { "," };
                foreach (string part in str.Split(separator, options))
                {
                    list.Add(part.ChangeTo<T>());
                }
            }
            return list;
        }
        /// <summary>
        /// 分割字符串。
        /// </summary>
        /// <typeparam name="T">分割后转换的类型。</typeparam>
        /// <param name="str">用于分割的字符串。</param>
        /// <param name="separator">分割字符。</param>
        /// <param name="options">是否移除空项。</param>
        /// <returns>返回分割后的列表。</returns>
        public static List<T> Split<T>(this string str, char separator, StringSplitOptions options = StringSplitOptions.RemoveEmptyEntries)
        {
            return str.Split<T>(new char[] { separator }, options);
        }
        /// <summary>
        /// 分割字符串。
        /// </summary>
        /// <typeparam name="T">分割后转换的类型。</typeparam>
        /// <param name="str">用于分割的字符串。</param>
        /// <param name="separator">分割字符串。</param>
        /// <param name="options">是否移除空项。</param>
        /// <returns>返回分割后的列表。</returns>
        public static List<T> Split<T>(this string str, string separator, StringSplitOptions options = StringSplitOptions.RemoveEmptyEntries)
        {
            return str.Split<T>(new string[] { separator }, options);
        }
        #endregion

        #region joins
        /// <summary>
        /// 将列表集合按一定的格式合成字符串。
        /// </summary>
        /// <param name="collection">列表实例对象。</param>
        /// <param name="separator">分割字符串。</param>
        /// <param name="execute">执行代理方法实例对象。</param>
        /// <returns>返回合成后的字符串。</returns>
        public static string Join(this NameValueCollection collection, string separator = ",", Func<string, string, string> execute = null)
        {
            if (collection == null)
                return string.Empty;

            StringBuilder builder = new StringBuilder();
            foreach (string key in collection.AllKeys)
            {
                if (builder.Length > 0)
                    builder.Append(separator);
                if (execute == null)
                    builder.AppendFormat("{0}={1}", key, collection[key]);
                else
                    builder.Append(execute(key, collection[key]));
            }
            return builder.ToString();
        }
        /// <summary>
        /// 将列表集合按一定的格式合成字符串。
        /// </summary>
        /// <param name="collection">列表实例对象。</param>
        /// <param name="separator">分割字符串。</param>
        /// <param name="execute">执行代理方法实例对象。</param>
        /// <returns>返回合成后的字符串。</returns>
        public static string Join(this IDictionary collection, string separator = ",", Func<string, object, string> execute = null)
        {
            if (collection == null)
                return string.Empty;

            StringBuilder builder = new StringBuilder();
            foreach (string key in collection.Keys)
            {
                if (builder.Length > 0)
                    builder.Append(separator);
                if (execute == null)
                    builder.AppendFormat("{0}={1}", key, collection[key]);
                else
                    builder.Append(execute(key, collection[key]));
            }
            return builder.ToString();
        }
        /// <summary>
        /// 将列表集合按一定的格式合成字符串。
        /// </summary>
        /// <typeparam name="TKey">字典键类型。</typeparam>
        /// <typeparam name="TValue">字典值类型。</typeparam>
        /// <param name="collection">列表实例对象。</param>
        /// <param name="separator">分割字符串。</param>
        /// <param name="execute">执行代理方法实例对象。</param>
        /// <returns>返回合成后的字符串。</returns>
        public static string Join<TKey, TValue>(this IDictionary<TKey, TValue> collection, string separator = ",", Func<KeyValuePair<TKey, TValue>, string> execute = null)
        {
            if (collection == null)
                return string.Empty;

            StringBuilder builder = new StringBuilder();
            foreach (var item in collection)
            {
                if (builder.Length > 0)
                    builder.Append(separator);
                if (execute == null)
                    builder.AppendFormat("{0}={1}", item.Key, item.Value);
                else
                    builder.Append(execute(item));
            }
            return builder.ToString();
        }
        /// <summary>
        /// 将列表集合按一定的格式合成字符串。
        /// </summary>
        /// <param name="collection">列表实例对象。</param>
        /// <param name="separator">分割字符串。</param>
        /// <param name="execute">执行代理方法实例对象。</param>
        /// <returns>返回合成后的字符串。</returns>
        public static string Join(this IEnumerable collection, string separator = ",", Func<object, string> execute = null)
        {
            if (collection == null)
                return string.Empty;
            
            StringBuilder builder = new StringBuilder();
            foreach (object value in collection)
            {
                if (value == null)
                    continue;
                if (builder.Length > 0)
                    builder.Append(separator);
                builder.Append(execute == null ? value.ToString() : execute(value));
            }
            return builder.ToString();
        }
        #endregion

        #region regexs
        private static readonly Regex emailRegex = new Regex(@"^[a-z0-9A-Z]+[\w\-\.]*@[a-z0-9\-]+(?>\.\w+){1,4}$", RegexOptions.Compiled | RegexOptions.Singleline | RegexOptions.IgnoreCase);
        #endregion

        #region random
        /// <summary>
        /// 随机生成字符串。
        /// </summary>
        /// <param name="seed">种子字符串。</param>
        /// <param name="length">长度（如果需要不同的字符串，本长度必须小于种子字符串的长度）。</param>
        /// <param name="defferent">是否生成不同的字符。</param>
        /// <returns>返回随机生成的字符串。</returns>
        public static string Random(this string seed, int length = 4, bool defferent = false)
        {
            if (string.IsNullOrEmpty(seed))
                seed = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
            if (seed.Length < length && defferent)
                throw new OutOfLengthException();
            List<char> randoms = new List<char>(length);
            var i = 0;
            Random rnd = new Random((int)DateTime.Now.Ticks);
            while (i < length)
            {
                char current = seed[(int)rnd.Next(0, seed.Length)];
                if (defferent)
                {
                    rnd = new Random((int)DateTime.Now.Ticks);
                    if (randoms.Contains(current))
                        continue;
                }
                randoms.Add(current);
                i++;
            }
            return randoms.Join("");
        }
        #endregion

        #region helpers
        /// <summary>
        /// 截取字符串。
        /// </summary>
        /// <param name="str">需要截取的字符串。</param>
        /// <param name="length">长度。</param>
        /// <param name="ending">截取后末尾添加的字符串。</param>
        /// <returns>返回截取后的字符串。</returns>
        public static string Truncate(this string str, int length, string ending = null)
        {
            if (str == null || str.Length <= length)
                return str;
            return str.Substring(0, length) + ending;
        }
        /// <summary>
        /// 文本忽略大小写替换。
        /// </summary>
        /// <param name="str">用于替换的字符串。</param>
        /// <param name="source">源字符。</param>
        /// <param name="replacement">文本替换后的字符。</param>
        /// <returns>返回替换后的字符串。</returns>
        public static string IgnoreCaseReplace(this string str, char source, char replacement)
        {
            return str.Replace(char.ToUpper(source), replacement).Replace(char.ToLower(source), replacement);
        }
        /// <summary>
        /// 文本忽略大小写替换。
        /// </summary>
        /// <param name="str">用于替换的字符串。</param>
        /// <param name="source">源字符串。</param>
        /// <param name="replacement">文本替换后的字符串。</param>
        /// <returns>返回替换后的字符串。</returns>
        public static string IgnoreCaseReplace(this string str, string source, string replacement)
        {
            if (str == null)
                return null;
            if (source == null)
                return str;
           return Regex.Replace(str, Regex.Escape(source), replacement, RegexOptions.Multiline|RegexOptions.IgnoreCase);
        }

        private static readonly Regex htmlRegex = new Regex("<(.[^>]*)>", RegexOptions.Multiline | RegexOptions.IgnoreCase | RegexOptions.Compiled);
        /// <summary>
        /// 移除HTML标签，并截取字符串。
        /// </summary>
        /// <param name="str">字符串。</param>
        /// <param name="length">长度，如果小于等于0表示不截取。</param>
        /// <param name="ending">超过长度后结尾字符串。</param>
        /// <param name="trim">移除HTML标签后是否移除字符串前后的空格。</param>
        /// <returns>返回移除处理后的字符串。</returns>
        public static string RemoveHTML(this string str, int length = -1, string ending = null, bool trim = true)
        {
            if (str == null)
                return null;
            str = htmlRegex.Replace(str, string.Empty);
            if (trim)
                str = str.Trim();
            if (length > 0)
                str = str.Truncate(length, ending);
            return str;
        }
        /// <summary>
        /// 判断字符串是否为日期值。
        /// </summary>
        /// <param name="str">当前字符串。</param>
        /// <returns>返回是否为日期值。</returns>
        public static bool IsDate(this string str) {
            try
            {
                Convert.ToDateTime(str);
                return true;
            }
            catch { }
            return false;
        }
        #endregion

        #region xml
        private static readonly int[] xmlCodes = new int[] { 0x26, 60, 0x3e, 0x22, 0x3d, 0x27 };

        /// <summary>
        /// 对XML字符串进行解码。
        /// </summary>
        /// <param name="xml">XML字符串。</param>
        /// <returns>返回XML字符串进行解码。</returns>
        public static string XMLDecode(this string xml)
        {
            for (int i = 0; i < xmlCodes.Length; i++)
            {
                xml = xml.Replace("&#" + xmlCodes[i].ToString() + ";", ((char)xmlCodes[i]).ToString());
            }
            return xml;
        }

        /// <summary>
        /// 对XML字符串进行XML编码。
        /// </summary>
        /// <param name="xml">XML字符串。</param>
        /// <returns>返回XML编码后的字符串。</returns>
        public static string XMLEncode(this string xml)
        {
            for (int i = 0; i < xmlCodes.Length; i++)
            {
                xml = xml.Replace(((char)xmlCodes[i]).ToString(), "&#" + xmlCodes[i].ToString() + ";");
            }
            return xml;
        }
        #endregion

        #region javascripts
        /// <summary>
        /// JavaScript格式化数值。
        /// </summary>
        /// <param name="value">用于格式化的值。</param>
        /// <returns>返回JavaScript格式化后的数值。</returns>
        public static string JSEncode(this double value)
        {
            return value.ToString("0.##", CultureInfo.InvariantCulture.NumberFormat);
        }
        /// <summary>
        /// JavaScript格式化数值。
        /// </summary>
        /// <param name="text">用于格式化的值。</param>
        /// <returns>返回JavaScript格式化后的数值。</returns>
        public static string JSEncode(this string text)
        {
            if (text == null)
                return null;
            return text.Replace(@"\", @"\\").Replace("\n", @"\n").Replace("\r", @"\r").Replace("'", @"\'").Replace("\"", "\\\"");
        }
        #endregion

        #region times
        /// <summary>
        /// 生成相同的字符串。
        /// </summary>
        /// <param name="str">字符串。</param>
        /// <param name="times">生成次数。</param>
        /// <returns>返回生成后的字符串。</returns>
        public static string Times(this string str, int times) {
            if (str == null || times < 1)
                return null;
            StringBuilder sb = new StringBuilder();
            for (var i = 0; i < times; i++) {
                sb.Append(str);
            }
            return sb.ToString();
        }
        /// <summary>
        /// 生成相同的字符。
        /// </summary>
        /// <param name="chr">字符。</param>
        /// <param name="times">生成个数。</param>
        /// <returns>返回生成后的字符串。</returns>
        public static string Times(this char chr, int times)
        {
            if (chr == '\0' || times <= 1)
                return chr+"";
            string str = "";
            for (var i = 0; i < times; i++)
            {
                str += chr;
            }
            return str;
        }
        #endregion
    }
}
